Projekt zaliczeniowy - Automatyczna Analiza Obrazu
Autor
Instytucja
Szymon Olędzki
Politechnika Lubelska
Cel projektu i charakterystyka zbioru danych
Celem niniejszego projektu jest stworzenie modelu konwolucyjnej sieci neuronowej, której zadaniem jest klasyfikacja 30 różnych rodzajów obiektów o kształcie okrągłym lub do niego zbliżonym.
Zbiór danych, który wykorzystałem do zrealizowania zadania to 30 Types of Balls Updated, dostępny na platformie Kaggle. Zawiera on 3895 zdjęć obiektów, podzielonych na następujące klasy:
0 - Baseball - piłki baseballowe
1 - Basketball - piłki do koszykówki
2 - Beachballs - piłki plażowe
3 - Billiard ball - bile bilardowe
4 - Bowling ball - kule do kręgli
5 - Brass - kule mosiężne
6 - Buckeyballs - fulereny
7 - Cannon ball - kule armatnie
8 - Crochet ball - piłki szydełkowane
9 - Cricket ball - piłki do krykieta
10 - Crystal ball - kule kryształowe
11 - Eyeballs - gałki oczne
12 - Football - piłki do futbolu amerykańskiego
13 - Golf ball - piłki golfowe
14 - Marble - kulki szklane
15 - Meat ball - klopsiki
16 - Medicine ball - piłki lekarskie
17 - Paint balls - kulki do paintballa
18 - Pokeman balls - Pokeballe
19 - Puffballs - purchawki
20 - Rubberband ball - piłki z gumek
21 - Screwballs - ludzkie twarze (ang. świrusy)
22 - Sepak takraw ball - piłki do sepak takraw
23 - Soccer ball - piłki nożne
24 - Tennis ball - piłki tenisowe
25 - Tether ball - piłki do tetherballa
26 - Volley ball - piłki do siatkówki
27 - Water polo ball - piłki do wodnego polo
28 - Wiffle ball - piłki do wiffle balla
29 - Wrecking ball - kule wyburzeniowe
Oryginalny zbiór podzielony jest na 3 foldery, dla zbiorów treningowego, walidacyjnego i testowego w taki sposób, by dla każdej z klas w zbiorze walidacyjnym i testowym było po 5 zdjęć. Nie jest to proporcja jaką chciałem zastosować przy uczeniu i ewaluacji modeli, zatem przed przystąpieniem do uczenia zmieniłem proporcję plików w poszczególnych zbiorach (70%/15%/15%).
Wykorzystane architektury sieci neuronowych
W ramach projektu uczenie przeprowadzę na 4 zaproponowanych przeze mnie autorskich architekturach oraz na 2 wcześniej nauczonych dostępnych w pakiecie Keras. Oprócz klasycznej metryki dokładności wyniki poszczególnych modeli porównam również dla metryk klasy top_n, dla 3 i 10 klas z największym prawdopodobieństwem.
Architektury własne
Pierwsza sieć
Jako pierwszą, “benchmarkową” architekturę wybrałem prostą sieć składającą się z trzech warstw kowolucyjnych (odpowiednio \(32\), \(64\) i \(128\) filtrów) połączonych warstwami max-pooling (rozmiar okna: \(2\times2\)) oraz jednej warstwy gęstej (\(512\) neuronów) poprzedzającej warstwę wyjściową.
Dla wszystkich warstw z wyjątkiem wyjściowej zastosowałem funkcję aktywacji ReLU, w przypadku tej ostatniej funkcją aktywacji jest Softmax.
Wybrana przeze mnie funkcja optymalizacji to Adam.
Sieć jest trenowana przez \(80\) epok z \(85\) krokami w każdej z nich.
Na pierwszy rzut oka można zauważyć ogromne przeuczenie, a dokładność na zbiorze walidacyjnym po 80 epokach osiąga ledwie \(0.25\). Wyniki dla metryk top3 i top10 również nie są satysfakcjonujące.
Druga sieć
Moja druga propozycja architektury opiera się na poprawieniu pierwszej propozycji przez wzgląd na jej duże przeuczenie. Tym razem po każdej warstwie konwolucyjnej zastosowałem batch normalization, żeby poprawić stabilność treningu, dodałem również warstwy dropout o wartościach współczynnika \(0.25\) po warstwach konwolucyjnych i \(0.5\) przed warstwą wyjściową oraz regularyzację L2 dla warstwy gęstej, żeby zmniejszyć przeuczenie.
Zmian dokonałem również w ramach optymalizatora - nadal jest to Adam, jednak tym razem z ustalonym współczynnikiem uczenia \(0.001\).
Do procesu uczenia dodałem również dwa callbacki:
Reduce Learning Rate on Plateau - dynamicznie zmniejsza współczynnik uczenia, gdy wynik modelu na zbiorze walidacyjnym przestaje się poprawiać po 5 epokach,
Early Stopping - pomaga zapobiegać przeuczeniu zatrzymując trening, gdy wynik modelu na zbiorze walidacyjnym przestaje się poprawiać po 10 epokach.
Model: "sequential_1"
________________________________________________________________________________
Layer (type) Output Shape Param # Trainable
================================================================================
conv2d_5 (Conv2D) (None, 222, 222, 32) 896 Y
batch_normalization_2 (Batch (None, 222, 222, 32) 128 Y
Normalization)
max_pooling2d_5 (MaxPooling2 (None, 111, 111, 32) 0 Y
D)
dropout_3 (Dropout) (None, 111, 111, 32) 0 Y
conv2d_4 (Conv2D) (None, 109, 109, 64) 18496 Y
batch_normalization_1 (Batch (None, 109, 109, 64) 256 Y
Normalization)
max_pooling2d_4 (MaxPooling2 (None, 54, 54, 64) 0 Y
D)
dropout_2 (Dropout) (None, 54, 54, 64) 0 Y
conv2d_3 (Conv2D) (None, 52, 52, 128) 73856 Y
batch_normalization (BatchNo (None, 52, 52, 128) 512 Y
rmalization)
max_pooling2d_3 (MaxPooling2 (None, 26, 26, 128) 0 Y
D)
dropout_1 (Dropout) (None, 26, 26, 128) 0 Y
flatten_1 (Flatten) (None, 86528) 0 Y
dense_3 (Dense) (None, 512) 44302848 Y
dropout (Dropout) (None, 512) 0 Y
dense_2 (Dense) (None, 30) 15390 Y
================================================================================
Total params: 44412382 (169.42 MB)
Trainable params: 44411934 (169.42 MB)
Non-trainable params: 448 (1.75 KB)
________________________________________________________________________________
Wyniki uczenia drugiej sieci
Zauważyć można zdecydowaną poprawę, jak widać zastosowane kroki przyniosły oczekiwany efekt, chociaż od pewnego momentu nadal można zaobserwować przeuczenie. Dokładność na zbiorze walidacyjnym wyniosła tym razem około \(0.5\), co jest zauważalnie lepszym, aczkolwiek nadal niesatysfakcjonującym wynikiem. Zastosowane callbacki również zadziałały skutecznie - sieć zakończyła uczenie wcześniej, gdy wynik na zbiorze walidacyjnym przestał się poprawiać, mimo założonych 80 epok uczenia. Metryka top3 wskazuje \(0.75\) dokładności, natomiast top10 ponad \(0.9\).
Trzecia sieć
Architektura trzeciej sieci różni się od poprzedniej w trzech aspektach. Zamiast jednej warstwy gęstej zastosowałem dwie, ale z mniejszą liczbą neuronów. Drugą zmianą jest zmniejszona wartość współczynnika we wszystkich warstwach dropout, tym razem dla wszystkich jest to \(0.2\).
Ostatnią zmianą jest zmniejszenie początkowego współczynnika uczenia przy optymalizatorze Adam na \(0.0001\). Stosuję nadal te same callbacki i uczenie przez 80 epok.
Model: "sequential_2"
________________________________________________________________________________
Layer (type) Output Shape Param # Trainable
================================================================================
conv2d_8 (Conv2D) (None, 222, 222, 32) 896 Y
max_pooling2d_8 (MaxPooling2 (None, 111, 111, 32) 0 Y
D)
batch_normalization_5 (Batch (None, 111, 111, 32) 128 Y
Normalization)
dropout_8 (Dropout) (None, 111, 111, 32) 0 Y
conv2d_7 (Conv2D) (None, 109, 109, 64) 18496 Y
max_pooling2d_7 (MaxPooling2 (None, 54, 54, 64) 0 Y
D)
batch_normalization_4 (Batch (None, 54, 54, 64) 256 Y
Normalization)
dropout_7 (Dropout) (None, 54, 54, 64) 0 Y
conv2d_6 (Conv2D) (None, 52, 52, 128) 73856 Y
max_pooling2d_6 (MaxPooling2 (None, 26, 26, 128) 0 Y
D)
batch_normalization_3 (Batch (None, 26, 26, 128) 512 Y
Normalization)
dropout_6 (Dropout) (None, 26, 26, 128) 0 Y
flatten_2 (Flatten) (None, 86528) 0 Y
dense_6 (Dense) (None, 128) 11075712 Y
dropout_5 (Dropout) (None, 128) 0 Y
dense_5 (Dense) (None, 64) 8256 Y
dropout_4 (Dropout) (None, 64) 0 Y
dense_4 (Dense) (None, 30) 1950 Y
================================================================================
Total params: 11180062 (42.65 MB)
Trainable params: 11179614 (42.65 MB)
Non-trainable params: 448 (1.75 KB)
________________________________________________________________________________
Wyniki uczenia trzeciej sieci
Widać, że zmiany przyniosły oczekiwany efekt, jest to delikatna, ale zauważalna zmiana - udało się przekroczyć próg \(0.6\) dokładności na zbiorze walidacyjnym i zmniejszyć przeuczenie. Wyniki dla metryk top3 i top10 nieznacząco się poprawiły.
Czwarta sieć
Czwarta i ostatnia propozycja mojej własnej architektury zawiera dodatkową warstwę konwolucyjną przed warstwami gęstymi. Zdecydowałem się na ten krok widząc, że w poprzedniej iteracji poprawę przyniosło dodanie warstwy gęstej. Dodana warstwa konwolucyjna zawiera (podobnie jak wcześniejsze warstwy) dwa razy więcej filtrów niż poprzednia. Postanowiłem zmienić również wartości współczynników w warstwach dropout, tym razem są wyższe i zwiększają się co dwie warstwy konwolucyjne.
Podobnie jak w przy poprzedniej architekturze nie zmieniałem optymalizatora, callbacków, ani czasu uczenia.
Model: "sequential_3"
________________________________________________________________________________
Layer (type) Output Shape Param # Trainable
================================================================================
conv2d_12 (Conv2D) (None, 222, 222, 32) 896 Y
batch_normalization_11 (Batc (None, 222, 222, 32) 128 Y
hNormalization)
max_pooling2d_12 (MaxPooling (None, 111, 111, 32) 0 Y
2D)
dropout_14 (Dropout) (None, 111, 111, 32) 0 Y
conv2d_11 (Conv2D) (None, 109, 109, 64) 18496 Y
batch_normalization_10 (Batc (None, 109, 109, 64) 256 Y
hNormalization)
max_pooling2d_11 (MaxPooling (None, 54, 54, 64) 0 Y
2D)
dropout_13 (Dropout) (None, 54, 54, 64) 0 Y
conv2d_10 (Conv2D) (None, 52, 52, 128) 73856 Y
batch_normalization_9 (Batch (None, 52, 52, 128) 512 Y
Normalization)
max_pooling2d_10 (MaxPooling (None, 26, 26, 128) 0 Y
2D)
dropout_12 (Dropout) (None, 26, 26, 128) 0 Y
conv2d_9 (Conv2D) (None, 24, 24, 256) 295168 Y
batch_normalization_8 (Batch (None, 24, 24, 256) 1024 Y
Normalization)
max_pooling2d_9 (MaxPooling2 (None, 12, 12, 256) 0 Y
D)
dropout_11 (Dropout) (None, 12, 12, 256) 0 Y
flatten_3 (Flatten) (None, 36864) 0 Y
dense_9 (Dense) (None, 128) 4718720 Y
batch_normalization_7 (Batch (None, 128) 512 Y
Normalization)
dropout_10 (Dropout) (None, 128) 0 Y
dense_8 (Dense) (None, 64) 8256 Y
batch_normalization_6 (Batch (None, 64) 256 Y
Normalization)
dropout_9 (Dropout) (None, 64) 0 Y
dense_7 (Dense) (None, 30) 1950 Y
================================================================================
Total params: 5120030 (19.53 MB)
Trainable params: 5118686 (19.53 MB)
Non-trainable params: 1344 (5.25 KB)
________________________________________________________________________________
Wyniki uczenia czwartej sieci
Po raz kolejny zauważyć można wzrost dokładności na zbiorze walidacyjnym, tym razem jest on bliski \(0.75\), jednak zwiększyło się również przeuczenie, względem poprzedniej architektury. Metryki top3 i top10 osiągnęły zadowalające wyniki - ok. \(0.9\) i \(0.95\).
Transfer Learning
Pakiet Keras udostępnia wstępnie wytrenowane modele, w tym DenseNet201 i VGG19, które są dostępne dla użytkowników do wykorzystania np. w ramach transfer learningu. Poniżej przedstawiam wyniki uczenia tych dwóch wybranych modeli na moim zbiorze danych. W obu przypadkach do gotowej architektury dodałem dwie warstwy gęste razem z warstwami batch normalization i dropout, podobnie jak w ostatniej autorskiej architekturze. Zastosowałem również ten sam optymalizator, callbacki oraz czas uczenia.
Model: "sequential_4"
________________________________________________________________________________
Layer (type) Output Shape Param # Trainable
================================================================================
densenet201 (Functional) (None, 7, 7, 1920) 18321984 N
global_average_pooling2d (Gl (None, 1920) 0 Y
obalAveragePooling2D)
dense_12 (Dense) (None, 128) 245888 Y
batch_normalization_13 (Batc (None, 128) 512 Y
hNormalization)
dropout_16 (Dropout) (None, 128) 0 Y
dense_11 (Dense) (None, 64) 8256 Y
batch_normalization_12 (Batc (None, 64) 256 Y
hNormalization)
dropout_15 (Dropout) (None, 64) 0 Y
dense_10 (Dense) (None, 30) 1950 Y
================================================================================
Total params: 18578846 (70.87 MB)
Trainable params: 256478 (1001.87 KB)
Non-trainable params: 18322368 (69.89 MB)
________________________________________________________________________________
Wyniki uczenia sieci DenseNet201
Jak widać model ten osiągnął dokładność podobną do czwartej proponowanej przeze mnie architektury, mając jednak zauważalnie niższe przeuczenie. Dla metryki top3 wynik również jest podobny, wartość metryki top10 poprawiła się.
Model: "sequential_5"
________________________________________________________________________________
Layer (type) Output Shape Param # Trainable
================================================================================
vgg19 (Functional) (None, 7, 7, 512) 20024384 N
global_average_pooling2d_1 ( (None, 512) 0 Y
GlobalAveragePooling2D)
dense_15 (Dense) (None, 128) 65664 Y
batch_normalization_15 (Batc (None, 128) 512 Y
hNormalization)
dropout_18 (Dropout) (None, 128) 0 Y
dense_14 (Dense) (None, 64) 8256 Y
batch_normalization_14 (Batc (None, 64) 256 Y
hNormalization)
dropout_17 (Dropout) (None, 64) 0 Y
dense_13 (Dense) (None, 30) 1950 Y
================================================================================
Total params: 20101022 (76.68 MB)
Trainable params: 76254 (297.87 KB)
Non-trainable params: 20024768 (76.39 MB)
________________________________________________________________________________
Wyniki uczenia sieci VGG19
Model sieci VGG19 osiągnął najlepszy wynik spośród wszystkich 6 modeli, deklasując konkurencję wynikiem ponad \(0.95\) dokładności na zbiorze walidacyjnym. Wartości metryki dokładności dla zbioru treningowego i walidacyjnego niemal się pokrywają, zatem efekt przeuczenia dla tego modelu jest najmniejszy. Metryki top3 i top10 osiągnęły wyniki zbliżone do \(1.0\).
Ewaluacja modeli
Ewaluację przeprowadzam dla dwóch modeli, które osiągnęły najlepsze wyniki na zbiorze walidacyjnym. Porównam zatem wyniki dla czwartej proponowanej przeze mnie architektury i sieci VGG19. Dla obu modeli przedstawię macierz konfuzji oraz przykładowe, błędnie sklasyfikowane obrazy ze zbioru testowego.
Na zbiorze testowym model osiągnął \(93.66\%\) dokładności.
Najczęstsza błędna predykcja: pokeballe jako kule do kręgli, piłki do wodnego polo jako piłki do siatkówki
Najgorzej przewidywana klasa: kulki do paintballa
Podsumowanie
Model sieci VGG19 okazał się być dużo dokładniejszy od proponowanej przeze mnie architektury, należy jednak pamiętać, że są to modele o zupełnie różnej złożoności (\(20.101.022\) parametrów vs. \(5.120.030\) parametrów). W przypadku problemu z aż 30 klasami, których obiekty mają wiele cech wspólnych uważam osiągnięte przeze mnie wyniki za dobre.